#include "RealTimeDealUtil.h"
#include "../BondContainer.h"
#include <core/Utility.h>
#include <uam/ServerTimeMgr.h>

namespace detail{
	bool MSUtil::IsBondRelativeType(const CBondInfo& info)
	{
		if (strcmp(info.GetListedMarket(), CBondContainer::lmCIB) != 0) return false;
		if (info.IsBondCountry()){//国债
			return true;
		}
		else if (info.IsBondGKZ()){
			return true;

		}
		else if (strcmp(info.GetBondSubType(), "PSB") != 0
			&& (strcmp(info.GetIssuerCode(), "Z000189") == 0 || strcmp(info.GetIssuerCode(), "Z000207") == 0)) {
			//非国开
			return true;
		}
		return false;

	}
	bool MSUtil::IsBondRelativeTerm(const CBondInfo& info)
	{
		std::string szBondPeriod;
		szBondPeriod = info.GetRemainPeriod(ServerTimeMgr::instance().serverTime());
		size_t nFind = szBondPeriod.find("Y");
		size_t nPlus = szBondPeriod.find("+");
		if (nFind == std::string::npos || (nPlus != std::string::npos && nFind != std::string::npos && nFind < nPlus))
			return false;
		if (nFind != std::string::npos)
			szBondPeriod.substr(0, nFind);
		if (szBondPeriod.length() > 0){
			float fRemainTime = atof(szBondPeriod.c_str());
			if ((fRemainTime >= 4 && fRemainTime <= 5.25) || (fRemainTime >= 6.5 && fRemainTime <= 10.25))
				return true;
		}
		return false;

	}
	double MSUtil::CalcRemainingDay(const std::string& sPrePeriod)
	{
		std::string sPeriod = sPrePeriod;
		if (sPeriod.empty())
			return -1;

		size_t pos = sPeriod.find("+");
		if (pos >= 2)
			sPeriod = sPeriod.substr(0, pos - 1);
		if (sPeriod[sPeriod.length() - 1] == 'Y')
		{
			return atof(sPeriod.substr(0, sPeriod.length() - 1).c_str()) * 365;
		}
		else if (sPeriod[sPeriod.length() - 1] == 'D')
		{
			return atof(sPeriod.substr(0, sPeriod.length() - 1).c_str());
		}
		else
			return -999;
	}
	void MSUtil::DecodeMarketStreamUnit(MarketStreamInfo& stInfo, const xQBMarketStreamUnit_c& unit)
	{
		memset(&stInfo, 0, sizeof(MarketStreamInfo));
		FIELDCOPY(stInfo.m_company_id, unit.m_company_id);
		//FIELDCOPY(stInfo.m_company_name, unit.m_company_name);
		FIELDCOPY(stInfo.m_dept, unit.m_dept);
		FIELDCOPY(stInfo.m_type, unit.m_type);
		FIELDCOPY(stInfo.m_operate, unit.m_operate);
		FIELDCOPY(stInfo.m_status, unit.m_status);
		FIELDCOPY(stInfo.m_body.m_quotetype, unit.m_body2.m_quotetype);
		//FIELDCOPY(stInfo.m_body.m_bondCode, unit.m_body2.m_bondCode);
		FIELDCOPY(stInfo.m_body.m_bondkey, unit.m_body2.m_bondkey);
		FIELDCOPY(stInfo.m_body.m_listedmarket, unit.m_body2.m_listedmarket);
		//FIELDCOPY(stInfo.m_body.m_bondShortName, unit.m_body2.m_bondShortName);
		FIELDCOPY(stInfo.m_body.m_price, unit.m_body2.m_price);
		FIELDCOPY(stInfo.m_body.m_volume, unit.m_body2.m_volume);
		FIELDCOPY(stInfo.m_body.m_fullPrice, unit.m_body2.m_fullPrice);
		FIELDCOPY(stInfo.m_body.m_cleanPrice, unit.m_body2.m_cleanPrice);
		FIELDCOPY(stInfo.m_body.m_yield, unit.m_body2.m_yield);
		FIELDCOPY(stInfo.m_body.m_rebate, unit.m_body2.m_rebate);
		FIELDCOPY(stInfo.m_body.m_return_point, unit.m_body2.m_return_point);
		FIELDCOPY(stInfo.m_body.m_id, unit.m_body2.m_id);
		FIELDCOPY(stInfo.m_body.m_dealStatus, unit.m_body2.m_dealStatus);
		FIELDCOPY(stInfo.m_body.m_exercise, unit.m_body2.m_exercise);
		stInfo.m_body.m_createTime = unit.m_body2.m_createTime;
		stInfo.m_modify_time = unit.m_modify_time;
		stInfo.m_create_time = unit.m_create_time;
		stInfo.m_indexID = unit.m_indexID;
	}
	void MSUtil::DecodeFIMarketStreamUnit(MarketStreamInfo& stInfo, const QbFixedIncomeDeal_c& unit)
	{
		memset(&stInfo, 0, sizeof(MarketStreamInfo));
		FIELDCOPY(stInfo.m_body.m_id, unit.m_Idx);
		FIELDCOPY(stInfo.m_body.m_bondkey, unit.m_BondKey);
		FIELDCOPY(stInfo.m_body.m_listedmarket, unit.m_ListedMarket);
		FIELDCOPY(stInfo.m_body.m_cleanPrice, unit.m_NetPrice);
		FIELDCOPY(stInfo.m_body.m_fullPrice, unit.m_FullPrice);
		FIELDCOPY(stInfo.m_body.m_yield, unit.m_YTM);
		FIELDCOPY(stInfo.m_body.m_volume, unit.m_Volume);
		FIELDCOPY(stInfo.m_body.m_price, unit.m_Amount);	//Amount暂存在price字段
		stInfo.m_body.m_createTime = unit.m_tDealTime;
		stInfo.m_modify_time = unit.m_tDealTime;
		stInfo.m_create_time = unit.m_tDealTime;
	}

	bool MSUtil::SortMarketRecord(const std::map<std::string, MarketStreamRec> &mapRecordTp, CMarketToprec &RecordInfo, CMarketToprec &MarketInfo, UINT nActvNum)
	{
		std::map<std::string, MarketStreamRec>::const_iterator itrAll = mapRecordTp.cbegin();
		for (; itrAll != mapRecordTp.cend(); itrAll++){
			if (itrAll->second.m_nTransCount > 0){
				for (int num = (int)nActvNum; num > 0; num--){
					if (RecordInfo.m_map[num].m_nTransCount < itrAll->second.m_nTransCount){
						if (num < (int)nActvNum)	RecordInfo.m_map[num + 1] = RecordInfo.m_map[num];
						RecordInfo.m_map[num] = itrAll->second;
						continue;
					}
					break;
				}
			}
		}
		if (RecordInfo.m_map.size() <= 0) return false;
		for (int num = 1; num <= (int)nActvNum; num++){
			if (std::string(RecordInfo.m_map[num].m_bondkey) == std::string(RecordInfo.m_map[num + 1].m_bondkey)
				&& std::string(RecordInfo.m_map[num].m_listedmarket) == std::string(RecordInfo.m_map[num + 1].m_listedmarket)){
				if (RecordInfo.m_map[num + 1].m_nTransCount>0)	MarketInfo.m_map[num] = RecordInfo.m_map[num];
				break;
			}
			else   MarketInfo.m_map[num] = RecordInfo.m_map[num];
		}
		return true;
	}
	bool MSUtil::InsertMarketRecord(const char* combondKey, const MarketStreamRec& rec, std::map<std::string, MarketStreamRec> &mapRecordTp)
	{
		//std::map<std::string, MarketStreamRec>::iterator itrRe
		if (!combondKey) return false;
        std::string stCur = combondKey;
		if (mapRecordTp.find(stCur) != mapRecordTp.end())
		{
			mapRecordTp[stCur].m_nTransCount += rec.m_nTransCount;
			if (rec.m_avePrice > 0.001){
				int nTmpcnt = mapRecordTp[stCur].m_nClanCount + 1;
				if (rec.m_avePrice <= 30){
					if (mapRecordTp[stCur].m_avePrice > 30){
						mapRecordTp[stCur] = rec;
					}
					else{
						mapRecordTp[stCur].m_avePrice = (mapRecordTp[stCur].m_avePrice*mapRecordTp[stCur].m_nRealCount + rec.m_avePrice) / (mapRecordTp[stCur].m_nRealCount + 1);
						mapRecordTp[stCur].m_nRealCount += 1;
					}
				}
				else{
					if (mapRecordTp[stCur].m_avePrice > 30){
						mapRecordTp[stCur].m_avePrice = mapRecordTp[stCur].m_aveclPrice = (mapRecordTp[stCur].m_aveclPrice*mapRecordTp[stCur].m_nClanCount + rec.m_avePrice) / nTmpcnt;
						mapRecordTp[stCur].m_nClanCount += 1;
					}
				}
			}
		}
		else
            mapRecordTp.insert(std::pair<std::string, MarketStreamRec>(combondKey, rec));
		return true;
	}

	CMarketStream::MarktType MSUtil::GetMarketStreamType(const char * szSubType, const char * szRateType)
	{
		if (strcmp(szSubType, "BGB") == 0 || strcmp(szSubType, "SGB") == 0 || strcmp(szSubType, "EGB") == 0){
			return CMarketStream::MarktCountry;
		}
		else if (strcmp(szSubType, "PBB") == 0 || strcmp(szSubType, "PSB") == 0
			|| strcmp(szSubType, "PDB") == 0)
		{
			if (strcmp(szRateType, "FIXED") == 0)	return CMarketStream::MarktFinance;
			else return CMarketStream::MarktNFRate;
		}
		else if (strcmp(szSubType, "CSP") == 0
			|| strcmp(szSubType, "LSP") == 0
			|| strcmp(szSubType, "LCP") == 0
			|| strcmp(szSubType, "SSB") == 0
			|| strcmp(szSubType, "CCP") == 0) {
			return CMarketStream::MarktShort;
		}
		else if (strcmp(szSubType, "LMN") == 0 || strcmp(szSubType, "CMN") == 0) {
			return CMarketStream::MarktChina;
		}
		else if (strcmp(szSubType, "LEB") == 0 || strcmp(szSubType, "CEB") == 0 || strcmp(szSubType, "RAB") == 0){
			return CMarketStream::MarktEnterpr;
		}
		else if (strcmp(szSubType, "COB") == 0
			|| strcmp(szSubType, "CBB") == 0
			|| strcmp(szSubType, "NCB") == 0
			|| strcmp(szSubType, "PPN") == 0
			|| strcmp(szSubType, "CSB") == 0
			|| strcmp(szSubType, "SEB") == 0
			|| strcmp(szSubType, "CVB") == 0
			|| strcmp(szSubType, "SCV") == 0
			|| strcmp(szSubType, "HJB") == 0
			|| strcmp(szSubType, "CCB") == 0
			|| strcmp(szSubType, "CXB") == 0
			|| strcmp(szSubType, "INT") == 0
			|| strcmp(szSubType, "MBS") == 0
			|| strcmp(szSubType, "LBS") == 0
			|| strcmp(szSubType, "CBS") == 0
			|| strcmp(szSubType, "AMP") == 0
			|| strcmp(szSubType, "SCB") == 0
			|| strcmp(szSubType, "TLB") == 0
			|| strcmp(szSubType, "LLB") == 0
			|| strcmp(szSubType, "MCD") == 0/*ncd*/
			|| strcmp(szSubType, "SPD") == 0
			|| strcmp(szSubType, "SHD") == 0
			|| strcmp(szSubType, "CCD") == 0
			|| strcmp(szSubType, "RRD") == 0
			|| strcmp(szSubType, "RTD") == 0
			|| strcmp(szSubType, "FRD") == 0
			|| strcmp(szSubType, "OTD") == 0
			|| strcmp(szSubType, "SES") == 0
			){
			return CMarketStream::MarktOther;
		}
		//else if(strcmp(szSubType,"PBB")==0 || strcmp(szSubType,"PSB")==0){ return CMarketStream::MarktNFRate;}
		else{ return  CMarketStream::MarktAll; }
	}
	bool MSUtil::DeletePrice(const MarketStreamInfo& info, MarketStreamRec& stRec)
	{
		if (info.IsDealStatusCanceled()) return true;
		if (stRec.m_nTransCount == 1)
		{
			stRec.m_avePrice = stRec.m_aveclPrice = 0.0;
			stRec.m_nRealCount = stRec.m_nClanCount = stRec.m_nTransCount = 0;
		}
		else if (strlen(info.m_body.m_price) > 0)
		{
			stRec.m_nTransCount = stRec.m_nTransCount - 1;
			if (atof(info.m_body.m_price) <= 30)
			{
				float fAvePrice = stRec.m_avePrice*stRec.m_nRealCount - atof(info.m_body.m_price);
				if (stRec.m_nRealCount == 1){
					stRec.m_avePrice = 0.0; stRec.m_nRealCount = 0;
					if (stRec.m_nClanCount > 0 && stRec.m_aveclPrice > 0.001) stRec.m_avePrice = stRec.m_aveclPrice;
				}
				else if (stRec.m_avePrice > 0.001){
					stRec.m_avePrice = (fAvePrice) / (stRec.m_nRealCount - 1);
					stRec.m_nRealCount = stRec.m_nRealCount - 1;
				}
			}
			else
			{
				int nTmpcnt = stRec.m_nClanCount - 1;
				float fAveClPrice = stRec.m_aveclPrice*stRec.m_nClanCount - atof(info.m_body.m_price);
				if (stRec.m_nClanCount == 1){ stRec.m_aveclPrice = 0.0; stRec.m_nClanCount = 0; }
				else if (stRec.m_aveclPrice > 0.001){
					stRec.m_aveclPrice = (fAveClPrice) / nTmpcnt;
					stRec.m_nClanCount = stRec.m_nClanCount - 1;
				}
			}
		}
		else
			stRec.m_nTransCount = stRec.m_nTransCount - 1;
		return true;
	}

	bool MSUtil::CaculateRecordPrice(MarketStreamRec& stRec, const MarketStreamInfo& info)
	{
		return CaculateRecordPrice(stRec, info.m_body.m_bondkey, info.m_body.m_listedmarket/*, info.m_body.m_bondCode*/, info.m_body.m_price);
	}

	bool MSUtil::CaculateRecordPrice(MarketStreamRec& stRec, const char* bondKey, const char* listMarket/*, const char* bondCode*/, const char* price)
	{
		//FIELDCOPY(stRec.m_bondCode, bondCode);
		FIELDCOPY(stRec.m_bondkey, bondKey);
		FIELDCOPY(stRec.m_listedmarket, listMarket);
		stRec.m_nTransCount = stRec.m_nTransCount + 1;
		if (strlen(price) > 0){
			int nTmpcnt = stRec.m_nClanCount + 1;
			if (atof(price) <= 30){
				if (stRec.m_avePrice < 0.001 || stRec.m_avePrice>30){
					FIELDCOPY(stRec.m_Maxprice, price);
					FIELDCOPY(stRec.m_Minprice, price);
					stRec.m_nRealCount = 1; stRec.m_avePrice = atof(price);
				}
				else {
					if (atof(price) < atof(stRec.m_Minprice)){
						FIELDCOPY(stRec.m_Minprice, price);
					}
					if (atof(price) > atof(stRec.m_Maxprice)){
						FIELDCOPY(stRec.m_Maxprice, price);
					}
					stRec.m_avePrice = (stRec.m_avePrice*stRec.m_nRealCount + atof(price)) / (stRec.m_nRealCount + 1); stRec.m_nRealCount = stRec.m_nRealCount + 1;
				}
			}
			else{
				if (stRec.m_avePrice < 0.001){
					stRec.m_avePrice = stRec.m_aveclPrice = atof(price);
				}
				else if (stRec.m_avePrice <= 30){ stRec.m_aveclPrice = (stRec.m_aveclPrice*stRec.m_nClanCount + atof(price)) / nTmpcnt; }
				else{
					if (atof(price) < atof(stRec.m_Minprice)){
						FIELDCOPY(stRec.m_Minprice, price);
					}
					if (atof(price) > atof(stRec.m_Maxprice)){
						FIELDCOPY(stRec.m_Maxprice, price);
					}
					stRec.m_avePrice = stRec.m_aveclPrice = (stRec.m_aveclPrice*stRec.m_nClanCount + atof(price)) / nTmpcnt;
				}
				stRec.m_nClanCount += 1;
			}
		}
		return true;
	}

	bool MSUtil::GetTodayMarketRecord(CMarketToprec &MarketInfo, const CMarketStreamlst &lst, UINT nActvNum)
	{
		CMarketToprec RecordInfo;
		std::map<std::string, MarketStreamRec> mapRecordTp;
		if (lst.m_Record.size() > 0){
			MarketInfo.SetSize(lst.m_list.size());
			for (std::map<std::string, MarketStreamRec>::const_iterator itrRe = lst.m_Record.begin(); itrRe != lst.m_Record.end(); itrRe++){
				MSUtil::InsertMarketRecord(itrRe->first.c_str(), itrRe->second, mapRecordTp);
			}
		}
		if (mapRecordTp.size() < 0) return false;
		bool bret = MSUtil::SortMarketRecord(mapRecordTp, RecordInfo, MarketInfo, nActvNum);
		return bret;
	}

}
